Xotiradan foydalanishni keskin kamaytirish va atributlarga kirish tezligini oshirish uchun Python __slots__ ni o'rganing. Benchmarking, kamchiliklar va eng yaxshi amaliyotlar bilan to'liq qo'llanma.
Python __slots__: Xotirani optimallashtirish va atribut tezligiga chuqur kirish
Dasturiy ta'minotni ishlab chiqish dunyosida unumdorlik eng muhim omil hisoblanadi. Python dasturchilari uchun bu ko'pincha tilning ajoyib moslashuvchanligi va resurs samaradorligiga bo'lgan ehtiyoj o'rtasidagi nozik muvozanatni o'z ichiga oladi. Eng keng tarqalgan muammolardan biri, ayniqsa, ma'lumotlarga boy ilovalarda, xotiradan foydalanishni boshqarishdir. Millionlab yoki hatto milliardlab kichik obyektlarni yaratganingizda, har bir bayt hisobga olinadi.
Aynan shu yerda Python'ning kamroq ma'lum, ammo kuchli xususiyati — __slots__
ishga tushadi. U ko'pincha xotirani optimallashtirish uchun sehrli vosita sifatida tilga olinadi, ammo uning asl tabiati ancha nozik. Bu faqat xotirani tejash haqidami? U chindan ham kodingizni tezlashtiradimi? Va uni ishlatishning yashirin xarajatlari qanday?
Ushbu keng qamrovli qo'llanma sizni Python'ning __slots__
xususiyatiga chuqur olib kiradi. Biz standart Python obyektlari qanday ishlashini tahlil qilamiz, __slots__
ning xotira va tezlikka bo'lgan haqiqiy ta'sirini benchmark orqali o'lchaymiz, uning ajablanarli murakkabliklari va kamchiliklarini o'rganamiz hamda ushbu kuchli optimallashtirish vositasini qachon ishlatish — va qachon ishlatmaslik kerakligi to'g'risida aniq yo'riqnoma taqdim etamiz.
Standart holat: Python obyektlari atributlarni `__dict__` yordamida qanday saqlaydi
__slots__
nima qilishini tushunishdan oldin, u nimani almashtirishini tushunib olishimiz kerak. Odatiy holatda, Python'dagi har bir maxsus klass nusxasi __dict__
deb nomlangan maxsus atributga ega. Bu, so'zma-so'z aytganda, nusxaning barcha atributlarini saqlaydigan lug'atdir.
Keling, oddiy misolni ko'rib chiqaylik: 2D nuqtani ifodalovchi klass.
import sys
class Point2D:
def __init__(self, x, y):
self.x = x
self.y = y
# Nusxa yaratish
p1 = Point2D(10, 20)
# Atributlar __dict__ da saqlanadi
print(p1.__dict__) # Chiqish: {'x': 10, 'y': 20}
# Keling, __dict__ ning o'zining hajmini tekshiramiz
print(f"Point2D nusxasining __dict__ hajmi: {sys.getsizeof(p1.__dict__)} bayt")
Chiqish sizning Python versiyangiz va tizim arxitekturangizga qarab biroz farq qilishi mumkin (masalan, kichik lug'at uchun Python 3.10+ da 64 bayt), ammo asosiy xulosa shundaki, bu lug'at o'zining xotira iziga ega bo'lib, u nusxa obyekti va u saqlaydigan qiymatlardan alohida.
Moslashuvchanlikning kuchi va narxi
Bu __dict__
yondashuvi Python dinamizmining asosidir. U sizga istalgan vaqtda nusxaga yangi atributlar qo'shish imkonini beradi, bu amaliyot ko'pincha "monkey-patching" deb ataladi:
# Yo'l-yo'lakay yangi atribut qo'shish
p1.z = 30
print(p1.__dict__) # Chiqish: {'x': 10, 'y': 20, 'z': 30}
Bu moslashuvchanlik tezkor rivojlanish va ma'lum dasturlash uslublari uchun ajoyibdir. Biroq, buning bir narxi bor: xotiraning ortiqcha sarflanishi.
Python'dagi lug'atlar yuqori darajada optimallashtirilgan, lekin ular tabiatan oddiyroq ma'lumotlar tuzilmalariga qaraganda murakkabroqdir. Ular tezkor kalit qidiruvlarini ta'minlash uchun xesh-jadvalni saqlashlari kerak, bu esa potentsial xesh to'qnashuvlarini boshqarish va samarali o'lcham o'zgartirishga imkon berish uchun qo'shimcha xotira talab qiladi. Millionlab Point2D
nusxalarini yaratganingizda, har biri o'zining __dict__
ga ega bo'lib, bu xotira sarfi tezda to'planib boradi.
Tasavvur qiling, 10 millionta cho'qqiga ega 3D modelni qayta ishlaydigan ilova bor. Agar har bir cho'qqi obyekti 64 baytlik __dict__
ga ega bo'lsa, bu faqatgina lug'atlar uchun 640 megabayt xotira sarflanishini anglatadi, ular saqlaydigan haqiqiy butun son yoki o'nli kasr qiymatlarini hisobga olmaganda! Aynan shu muammoni __slots__
hal qilish uchun yaratilgan.
`__slots__` bilan tanishuv: Xotirani tejaydigan alternativa
__slots__
— bu nusxada bo'ladigan atributlarni aniq e'lon qilishga imkon beruvchi klass o'zgaruvchisidir. __slots__
ni belgilash orqali siz aslida Python'ga shunday deysiz: "Ushbu klassning nusxalari faqat mana shu maxsus atributlarga ega bo'ladi. Ular uchun __dict__
yaratishning hojati yo'q."
Lug'at o'rniga, Python nusxa uchun xotirada belgilangan miqdorda joy ajratadi, bu joy e'lon qilingan atributlar qiymatlariga ko'rsatkichlarni saqlash uchun yetarli, xuddi C struct yoki tuple kabi.
Keling, Point2D
klassimizni __slots__
dan foydalanish uchun qayta yozamiz.
class SlottedPoint2D:
# Nusxa atributlarini e'lon qilish
# Bu tuple (eng keng tarqalgan), list yoki satrlardan iborat har qanday iterable bo'lishi mumkin.
__slots__ = ('x', 'y')
def __init__(self, x, y):
self.x = x
self.y = y
Tashqi ko'rinishidan u deyarli bir xil ko'rinadi. Ammo ichkarida hamma narsa o'zgargan. __dict__
yo'qoldi.
p_slotted = SlottedPoint2D(10, 20)
# __dict__ ga kirishga urinish xatolikni keltirib chiqaradi
try:
print(p_slotted.__dict__)
except AttributeError as e:
print(e) # Chiqish: 'SlottedPoint2D' obyekti '__dict__' atributiga ega emas
Xotira tejamkorligini o'lchash
Haqiqiy "voy" deydigan lahza xotiradan foydalanishni solishtirganimizda keladi. Buni to'g'ri bajarish uchun obyekt hajmi qanday o'lchanishini tushunishimiz kerak. sys.getsizeof()
obyektning asosiy hajmini bildiradi, lekin u havola qiladigan narsalarning, masalan, __dict__
ning hajmini emas.
import sys
# --- Oddiy Klass ---
class Point2D:
def __init__(self, x, y):
self.x = x
self.y = y
# --- Slotted Klass ---
class SlottedPoint2D:
__slots__ = ('x', 'y')
def __init__(self, x, y):
self.x = x
self.y = y
# Taqqoslash uchun har biridan bitta nusxa yaratamiz
p_normal = Point2D(1, 2)
p_slotted = SlottedPoint2D(1, 2)
# Slotted nusxaning hajmi ancha kichik
# Odatda bu asosiy obyekt hajmi va har bir slot uchun ko'rsatkich.
size_slotted = sys.getsizeof(p_slotted)
# Oddiy nusxaning hajmi uning asosiy hajmini va __dict__ ga ko'rsatkichni o'z ichiga oladi.
# Umumiy hajm - bu nusxa hajmi + __dict__ hajmi.
size_normal = sys.getsizeof(p_normal) + sys.getsizeof(p_normal.__dict__)
print(f"Bitta SlottedPoint2D nusxasining hajmi: {size_slotted} bayt")
print(f"Bitta Point2D nusxasining umumiy xotira izi: {size_normal} bayt")
# Endi keling, keng miqyosdagi ta'sirini ko'ramiz
NUM_INSTANCES = 1_000_000
# Haqiqiy ilovada siz memory_profiler kabi vositadan foydalanasiz
# jarayonning umumiy xotira sarfini o'lchash uchun.
# Biz bitta nusxa hisob-kitobiga asoslanib tejashni taxmin qilishimiz mumkin.
size_diff_per_instance = size_normal - size_slotted
total_memory_saved = size_diff_per_instance * NUM_INSTANCES
print(f"\n{NUM_INSTANCES:,} ta nusxa yaratilmoqda...")
print(f"__slots__ dan foydalanish orqali har bir nusxada tejalgan xotira: {size_diff_per_instance} bayt")
print(f"Taxminiy umumiy tejalgan xotira: {total_memory_saved / (1024*1024):.2f} MB")
Odatdagi 64-bitli tizimda har bir nusxada 40-50% xotira tejalishini kutish mumkin. Oddiy obyekt o'zining asosi uchun 16 bayt + __dict__
ko'rsatkichi uchun 8 bayt + bo'sh __dict__
uchun 64 bayt, jami 88 bayt talab qilishi mumkin. Ikki atributli slotted obyekt esa faqat 32 bayt talab qilishi mumkin. Har bir nusxadagi bu ~56 baytlik farq bir million nusxa uchun 56 MB tejalishini anglatadi. Bu mikro-optimallashtirish emas; bu imkonsiz ilovani imkonli qilishga qodir bo'lgan fundamental o'zgarishdir.
Ikkinchi va'da: Atributlarga tezroq kirish
Xotirani tejashdan tashqari, __slots__
unumdorlikni oshirish bilan ham mashhur. Nazariya to'g'ri: belgilangan xotira ofsetidan qiymatga kirish (massiv indeksi kabi) lug'atda xesh qidiruvini amalga oshirishdan tezroq.
__dict__
orqali kirish:obj.x
'x'
kaliti uchun lug'at qidiruvini o'z ichiga oladi.__slots__
orqali kirish:obj.x
ma'lum bir slotga to'g'ridan-to'g'ri xotiraga kirishni o'z ichiga oladi.
Ammo amalda bu qanchalik tezroq? Keling, Python'ning o'rnatilgan timeit
modulidan foydalanib bilib olamiz.
import timeit
# Vaqtni o'lchashdan oldin bir marta ishga tushiriladigan sozlash kodi
SETUP_CODE = """
class Point2D:
def __init__(self, x, y):
self.x = x
self.y = y
class SlottedPoint2D:
__slots__ = 'x', 'y'
def __init__(self, x, y):
self.x = x
self.y = y
p_normal = Point2D(1, 2)
p_slotted = SlottedPoint2D(1, 2)
"""
# Atribut o'qishni test qilish
read_normal = timeit.timeit("p_normal.x", setup=SETUP_CODE, number=10_000_000)
read_slotted = timeit.timeit("p_slotted.x", setup=SETUP_CODE, number=10_000_000)
print("--- Atribut o'qish ---")
print(f"__dict__ orqali kirish vaqti: {read_normal:.4f} soniya")
print(f"__slots__ orqali kirish vaqti: {read_slotted:.4f} soniya")
speedup = (read_normal - read_slotted) / read_normal * 100
print(f"Tezlashuv: {speedup:.2f}%")
print("\n--- Atribut yozish ---")
# Atribut yozishni test qilish
write_normal = timeit.timeit("p_normal.x = 3", setup=SETUP_CODE, number=10_000_000)
write_slotted = timeit.timeit("p_slotted.x = 3", setup=SETUP_CODE, number=10_000_000)
print(f"__dict__ orqali kirish vaqti: {write_normal:.4f} soniya")
print(f"__slots__ orqali kirish vaqti: {write_slotted:.4f} soniya")
speedup = (write_normal - write_slotted) / write_normal * 100
print(f"Tezlashuv: {speedup:.2f}%")
Natijalar __slots__
haqiqatan ham tezroq ekanligini ko'rsatadi, ammo yaxshilanish odatda 10-20% oralig'ida bo'ladi. Bu ahamiyatsiz bo'lmasa-da, xotira tejamkorligi kabi keskin emas.
Asosiy xulosa: __slots__
ni asosan xotirani optimallashtirish uchun ishlating. Tezlikni oshirishni yoqimli, ammo ikkinchi darajali bonus deb hisoblang. Unumdorlikning o'sishi, atributlarga millionlab marta murojaat qilinadigan, hisoblash jihatidan intensiv algoritmlar ichidagi qattiq sikllarda eng dolzarbdir.
Kamchiliklar va "Tuzoqlar": `__slots__` bilan nimalarni yo'qotasiz
__slots__
tekin tushlik emas. Unumdorlikning o'sishi moslashuvchanlik hisobiga keladi va ba'zi murakkabliklarni, ayniqsa vorislik bilan bog'liq holda, kiritadi. Ushbu kamchiliklarni tushunish __slots__
ni samarali ishlatish uchun juda muhimdir.
1. Dinamik atributlarning yo'qolishi
Bu eng muhim oqibatdir. Atributlarni oldindan belgilash orqali siz ish vaqtida yangilarini qo'shish imkoniyatini yo'qotasiz.
p_slotted = SlottedPoint2D(10, 20)
# Bu yaxshi ishlaydi
p_slotted.x = 100
# Bu esa muvaffaqiyatsiz bo'ladi
try:
p_slotted.z = 30 # 'z' __slots__ da emas edi
except AttributeError as e:
print(e) # Chiqish: 'SlottedPoint2D' obyekti 'z' atributiga ega emas
Bu xatti-harakat xato emas, balki xususiyat bo'lishi mumkin. U qat'iyroq obyekt modelini joriy qiladi, tasodifiy atribut yaratilishining oldini oladi va klassning "shakli" ni yanada bashorat qilinadigan qiladi. Biroq, agar sizning dizayningiz dinamik atribut tayinlashiga bog'liq bo'lsa, __slots__
mos kelmaydi.
2. `__dict__` va `__weakref__` ning yo'qligi
Ko'rib turganimizdek, __slots__
__dict__
yaratilishiga to'sqinlik qiladi. Bu, agar siz __dict__
orqali introspeksiyaga tayanadigan kutubxonalar yoki vositalar bilan ishlashingiz kerak bo'lsa, muammoli bo'lishi mumkin.
Shunga o'xshab, __slots__
avtomatik ravishda __weakref__
yaratilishiga ham to'sqinlik qiladi, bu atribut obyektning zaif havola qilinishi uchun zarurdir. Zaif havolalar — bu obyektlarni kuzatib borish uchun ishlatiladigan ilg'or xotirani boshqarish vositasi bo'lib, ularning axlat yig'uvchi tomonidan yo'q qilinishiga to'sqinlik qilmaydi.
Yechim: Agar sizga kerak bo'lsa, '__dict__'
va '__weakref__'
ni __slots__
ta'rifingizga aniq kiritishingiz mumkin.
class HybridSlottedPoint:
# Biz x va y uchun xotirani tejaymiz, lekin hali ham __dict__ va __weakref__ ga egamiz
__slots__ = ('x', 'y', '__dict__', '__weakref__')
def __init__(self, x, y):
self.x = x
self.y = y
p_hybrid = HybridSlottedPoint(5, 10)
p_hybrid.z = 20 # Bu endi ishlaydi, chunki __dict__ mavjud!
print(p_hybrid.__dict__) # Chiqish: {'z': 20}
import weakref
w_ref = weakref.ref(p_hybrid) # Bu ham endi ishlaydi
print(w_ref)
'__dict__'
qo'shish sizga gibrid modelni beradi. Slotted atributlar (x
, y
) hali ham samarali ishlanadi, boshqa har qanday atributlar esa __dict__
ga joylashtiriladi. Bu xotira tejamkorligining bir qismini yo'qqa chiqaradi, lekin eng keng tarqalgan atributlarni optimallashtirish bilan birga moslashuvchanlikni saqlab qolish uchun foydali murosaga kelish bo'lishi mumkin.
3. Vorislikning murakkabliklari
Aynan shu yerda __slots__
qiyinlashishi mumkin. Uning xatti-harakati ota va bola klasslari qanday belgilanganiga qarab o'zgaradi.
Yakka vorislik
-
Agar ota klassda
__slots__
bo'lsa-yu, bolada bo'lmasa: Bola klass ota atributlari uchun slotted xususiyatni meros qilib oladi, lekin o'zining__dict__
iga ham ega bo'ladi. Bu bola klass nusxalari ota nusxalaridan kattaroq bo'lishini anglatadi.class SlottedBase: __slots__ = ('a',) class DictChild(SlottedBase): # Bu yerda __slots__ belgilanmagan def __init__(self): self.a = 1 self.b = 2 # 'b' __dict__ da saqlanadi c = DictChild() print(f"Bolada __dict__ bormi: {hasattr(c, '__dict__')}") # Chiqish: True print(c.__dict__) # Chiqish: {'b': 2}
-
Agar ota va bola klasslarida
__slots__
belgilangan bo'lsa: Bola klass__dict__
ga ega bo'lmaydi. Uning samarali__slots__
i o'zining__slots__
i va otasining__slots__
i birikmasi bo'ladi.class SlottedBase: __slots__ = ('a',) class SlottedChild(SlottedBase): __slots__ = ('b',) # Samarali slotlar ('a', 'b') def __init__(self): self.a = 1 self.b = 2 sc = SlottedChild() print(f"Bolada __dict__ bormi: {hasattr(sc, '__dict__')}") # Chiqish: False try: sc.c = 3 # AttributeError ni keltirib chiqaradi except AttributeError as e: print(e)
__slots__
i bolaning__slots__
ida ham ro'yxatga olingan atributni o'z ichiga olsa, bu ortiqcha, lekin odatda zararsiz.
Ko'p vorislik
__slots__
bilan ko'p vorislik minalangan maydonga o'xshaydi. Qoidalar qat'iy va kutilmagan xatolarga olib kelishi mumkin.
-
Asosiy qoida: Bola klassning
__slots__
ni samarali ishlatishi uchun (ya'ni,__dict__
siz), uning barcha ota klasslari ham__slots__
ga ega bo'lishi kerak. Agar hatto bitta ota klassda__slots__
bo'lmasa (va shuning uchun__dict__
ga ega bo'lsa), bola klass ham__dict__
ga ega bo'ladi. -
`TypeError` tuzog'i: Bola klass bir vaqtning o'zida bo'sh bo'lmagan
__slots__
ga ega bo'lgan bir nechta ota klassdan vorislik qila olmaydi.class SlotParentA: __slots__ = ('x',) class SlotParentB: __slots__ = ('y',) try: class ProblemChild(SlotParentA, SlotParentB): pass except TypeError as e: print(e) # Chiqish: multiple bases have instance lay-out conflict
Hukm: `__slots__` ni qachon ishlatish va qachon ishlatmaslik kerak
Afzalliklar va kamchiliklarni aniq tushungan holda, biz amaliy qaror qabul qilish tizimini yaratishimiz mumkin.
Yashil bayroqlar: `__slots__` ni qachon ishlatish kerak...
- Siz juda ko'p sonli nusxalar yaratayotgan bo'lsangiz. Bu asosiy qo'llanilish holati. Agar siz millionlab obyektlar bilan ishlayotgan bo'lsangiz, xotira tejamkorligi ishlaydigan va ishdan chiqadigan ilova o'rtasidagi farq bo'lishi mumkin.
-
Obyektning atributlari o'zgarmas va oldindan ma'lum bo'lsa.
__slots__
ma'lumotlar tuzilmalari, yozuvlar yoki "shakli" o'zgarmaydigan oddiy ma'lumot obyektlari uchun juda mos keladi. - Siz xotirasi cheklangan muhitda bo'lsangiz. Bunga IoT qurilmalari, mobil ilovalar yoki har bir megabayt qimmatli bo'lgan yuqori zichlikdagi serverlar kiradi.
-
Siz unumdorlikning zaif nuqtasini optimallashtirayotgan bo'lsangiz. Agar profillash qattiq sikl ichidagi atributlarga kirish sezilarli sekinlashuv ekanligini ko'rsatsa,
__slots__
dan olingan kichik tezlik o'sishi bunga arziydi.
Keng tarqalgan misollar:
- Katta graf yoki daraxt tuzilmasidagi tugunlar.
- Fizik simulyatsiyadagi zarralar.
- Katta ma'lumotlar bazasi so'rovidan olingan qatorlarni ifodalovchi obyektlar.
- Yuqori o'tkazuvchanlik tizimidagi hodisa yoki xabar obyektlari.
Qizil bayroqlar: `__slots__` dan qachon qochish kerak...
-
Moslashuvchanlik muhim bo'lsa. Agar sizning klassingiz umumiy maqsadlarda foydalanish uchun mo'ljallangan bo'lsa yoki siz dinamik ravishda atributlar qo'shishga (monkey-patching) tayansangiz, standart
__dict__
dan foydalaning. -
Sizning klassingiz boshqalar tomonidan vorislik uchun mo'ljallangan ommaviy API ning bir qismi bo'lsa. Asosiy klassga
__slots__
ni yuklash barcha bola klasslarga cheklovlar qo'yadi, bu esa foydalanuvchilaringiz uchun kutilmagan syurpriz bo'lishi mumkin. -
Siz ahamiyatli bo'lishi uchun yetarlicha nusxalar yaratmayotgan bo'lsangiz. Agar sizda faqat bir necha yuz yoki ming nusxa bo'lsa, xotira tejamkorligi sezilarsiz bo'ladi. Bu yerda
__slots__
ni qo'llash hech qanday real foyda keltirmaydigan va murakkablikni oshiradigan muddatidan oldin optimallashtirishdir. -
Siz murakkab ko'p vorislik ierarxiyalari bilan ishlayotgan bo'lsangiz.
TypeError
cheklovlari bu stsenariylarda__slots__
ni foydasidan ko'ra ko'proq muammo keltirib chiqarishi mumkin.
Zamonaviy alternativlar: `__slots__` hali ham eng yaxshi tanlovmi?
Python ekotizimi rivojlandi va __slots__
endi yengil obyektlar yaratish uchun yagona vosita emas. Zamonaviy Python kodi uchun siz ushbu ajoyib alternativlarni ko'rib chiqishingiz kerak.
`collections.namedtuple` va `typing.NamedTuple`
Namedtuples nomlangan maydonlarga ega tuple subklasslarini yaratish uchun fabrika funksiyasidir. Ular juda tejamkor (hatto slotted obyektlardan ham ko'proq, chunki ular tubdan tuple'dir) va eng muhimi, o'zgarmasdir.
from typing import NamedTuple
# Tip izohlari bilan o'zgarmas klass yaratadi
class Point(NamedTuple):
x: int
y: int
p = Point(10, 20)
print(p.x) # 10
try:
p.x = 30 # AttributeError ni keltirib chiqaradi: atributni o'rnatib bo'lmaydi
except AttributeError as e:
print(e)
Agar sizga o'zgarmas ma'lumotlar konteyneri kerak bo'lsa, NamedTuple
ko'pincha slotted klassdan yaxshiroq va soddaroq tanlovdir.
Ikkala dunyoning eng yaxshisi: `@dataclass(slots=True)`
Python 3.7 da taqdim etilgan va Python 3.10 da takomillashtirilgan dataklasslar o'yinni o'zgartiruvchi vositadir. Ular avtomatik ravishda __init__
, __repr__
va __eq__
kabi metodlarni yaratadi, bu esa shablon kodni keskin kamaytiradi.
Eng muhimi, @dataclass
dekoratorida slots
argumenti mavjud (Python 3.10 dan boshlab mavjud; Python 3.8-3.9 uchun xuddi shunday qulaylik uchun uchinchi tomon kutubxonasi kerak). slots=True
ni o'rnatganingizda, dataklass belgilangan maydonlarga asoslangan holda avtomatik ravishda __slots__
atributini yaratadi.
from dataclasses import dataclass
@dataclass(slots=True)
class DataPoint:
x: int
y: int
dp = DataPoint(10, 20)
print(dp) # Chiqish: DataPoint(x=10, y=20) - tekinga chiroyli repr!
print(hasattr(dp, '__dict__')) # Chiqish: False - slotlar yoqilgan!
Bu yondashuv sizga barcha dunyolarning eng yaxshisini beradi:
- O'qilishi oson va ixchamlik: Qo'lda yozilgan klass ta'rifidan ancha kam shablon kod.
- Qulaylik: Avtomatik yaratilgan maxsus metodlar sizni umumiy shablon kod yozishdan qutqaradi.
- Unumdorlik:
__slots__
ning to'liq xotira va tezlik afzalliklari. - Tip xavfsizligi: Python'ning tip tizimi bilan mukammal integratsiyalashadi.
Python 3.10+ da yozilgan yangi kod uchun, oddiy, o'zgaruvchan, xotira jihatidan samarali ma'lumotlarni saqlovchi klasslar yaratish uchun `@dataclass(slots=True)` sizning standart tanlovingiz bo'lishi kerak.
Xulosa: Maxsus vazifa uchun kuchli vosita
__slots__
Python'ning unumdorlik chegaralarini oshirishi kerak bo'lgan dasturchilar uchun kuchli vositalarni taqdim etish dizayn falsafasining isbotidir. Bu beg'araz ishlatiladigan xususiyat emas, balki aniq va keng tarqalgan muammoni hal qilish uchun o'tkir, aniq asbobdir: ko'p sonli kichik obyektlarning yuqori xotira sarfi.
Keling, __slots__
haqidagi muhim haqiqatlarni takrorlaymiz:
- Uning asosiy afzalligi xotiradan foydalanishni sezilarli darajada kamaytirishdir, ko'pincha nusxalar hajmini 40-50% ga qisqartiradi. Bu uning eng muhim xususiyatidir.
- U atributlarga kirish uchun ikkinchi darajali, kamtarroq tezlikni oshirishni ta'minlaydi, odatda 10-20% atrofida.
- Asosiy kamchilik - dinamik atribut tayinlash imkoniyatining yo'qolishi, bu qattiq obyekt tuzilishini talab qiladi.
- U vorislik bilan murakkablikni keltirib chiqaradi, ayniqsa ko'p vorislik stsenariylarida ehtiyotkorlik bilan dizayn qilishni talab qiladi.
-
Zamonaviy Python'da, `@dataclass(slots=True)` ko'pincha yuqoriroq, qulayroq alternativadir, u
__slots__
afzalliklarini dataklasslarning nafisligi bilan birlashtiradi.
Bu yerda optimallashtirishning oltin qoidasi amal qiladi: avval profillash. Sehrli tezlashuvga umid qilib, kodingizga __slots__
ni sepib chiqmang. Qaysi obyektlar eng ko'p xotira iste'mol qilayotganini aniqlash uchun xotirani profillash vositalaridan foydalaning. Agar siz millionlab marta yaratilayotgan va katta xotira iste'molchisi bo'lgan klassni topsangiz, unda — va faqat o'shanda — __slots__
ga murojaat qilish vaqti kelgan bo'ladi. Uning kuchini va xavflarini tushunib, siz undan global auditoriya uchun yanada samarali va kengaytiriladigan Python ilovalarini yaratishda samarali foydalanishingiz mumkin.